package com.gwz.wxtime.chessboard.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.cglib.CglibUtil;
import com.alibaba.fastjson.JSON;
import com.gwz.wxtime.chessboard.entity.*;
import com.gwz.wxtime.chessboard.util.PukeUtil;
import com.gwz.wxtime.core.consts.RedisKeyConst;
import com.gwz.wxtime.core.entity.base.BaseDTO;
import com.gwz.wxtime.core.entity.wx.GroupReceiveMessage;
import com.gwz.wxtime.core.service.BaseService;
import com.gwz.wxtime.core.util.WxUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@Order(1)
@Slf4j
public class DouDiZhuService implements BaseService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Override
    public boolean handGroupReceivedMessage(BaseDTO<BaseDTO<GroupReceiveMessage>> dto) {
        log.info("斗地主请求");
        BaseDTO<GroupReceiveMessage> data = dto.getData();

        if (data.getData().getMsg().equals("斗地主")) {
            douDiZhuInstruction(data.getData());
            return true;
        }


        if (data.getData().getMsg().startsWith("加入房间#")) {
            return findRoom(data.getData());
        }
        PlayRedis playInfo = getPlayInfo(data.getData().getFromWxid(), data.getData().getFinalFromWxid());
        if (playInfo == null) {
            //WxUtil.sendMessage(data.getData().getFromWxid(), WxUtil.at(data.getData().getFinalFromWxid()) + " ");
            return false;
        }


        if (data.getData().getMsg().startsWith("创建房间#")) {
            createRoom(data.getData());
            return true;
        } else if (data.getData().getMsg().startsWith("加入房间#")) {
            joinRoom(data.getData());
            return true;
        } else if (data.getData().getMsg().startsWith("退出房间")) {
            exitRoom(data.getData());
            return true;
        } else if (data.getData().getMsg().equals("开始")) {
            startGame(data.getData());
            return true;
        } else if (data.getData().getMsg().equals("抢地主") || data.getData().getMsg().equals("不抢")) {
            qiangDiZhu(data.getData());
            return true;
        } else if (data.getData().getMsg().equals("不要") || data.getData().getMsg().equals("pass")  || data.getData().getMsg().equals("要不起")) {
            noPlayCard(data.getData());
            return true;
        } else if (data.getData().getMsg().startsWith("出#") || data.getData().getMsg().startsWith("q#") || data.getData().getMsg().startsWith("go#") || data.getData().getMsg().startsWith("#")) {
            playCard(data.getData());
            return true;
        }
        return false;
    }


    private void douDiZhuInstruction(GroupReceiveMessage data) {

        PlayRedis playRedis = new PlayRedis();
        playRedis.setWxId(data.getFinalFromWxid());
        playRedis.setPositionWxid(data.getFromWxid());
        String redisKey = StrUtil.format(RedisKeyConst.DouDiZhuPlayInfo, data.getFinalFromWxid(), data.getFromWxid());
        if (Boolean.FALSE.equals(redisTemplate.hasKey(redisKey))) {
            redisTemplate.opsForValue().set(redisKey, playRedis, 36, TimeUnit.HOURS);
        }
        String wuZiQiRedisKey = StrUtil.format(RedisKeyConst.WuZiQiPlayInfo, data.getFinalFromWxid(), data.getFromWxid());
        redisTemplate.delete(wuZiQiRedisKey);

        WxUtil.sendMessage(data.getFromWxid(), WxUtil.at(data.getFinalFromWxid()) + " 斗地主指令 [玫瑰][玫瑰][玫瑰][玫瑰][玫瑰][玫瑰]\n" + "创建房间:  创建房间#房间号\n" + "加入房间:   加入房间#房间号\n" + "退出房间:   退出房间#房间号\n" + "准备:   准备\n" + "抢地主:   抢地主\n" + "出:  出#3#4#5#6#7\n" + "跳过:  跳过\n" + "tips: 三人准备 游戏自动开始");

    }


    private void createRoom(GroupReceiveMessage data) {
        try {
            String msg = data.getMsg();
            String roomNo = msg.split("#")[1];
            String redisKey = StrUtil.format(RedisKeyConst.DouDiZhuRoomInfo, data.getFromWxid(), roomNo);

            if (Boolean.TRUE.equals(redisTemplate.hasKey(redisKey))) {
                WxUtil.sendMessage(data.getFromWxid(), WxUtil.at(data.getFinalFromWxid()) + "房间已存在");
                return;
            }

            String playRedisKey = StrUtil.format(RedisKeyConst.DouDiZhuPlayInfo, data.getFinalFromWxid(), data.getFromWxid());
            PlayRedis playRedis = (PlayRedis) redisTemplate.opsForValue().get(playRedisKey);

            // 之前有房间置空
            if (StrUtil.isNotEmpty(playRedis.getRoomNo())) {
                String oldRedisRoomKey = StrUtil.format(RedisKeyConst.DouDiZhuRoomInfo, data.getFromWxid(), playRedis.getRoomNo());
                RoomRedis roomRedis = (RoomRedis) redisTemplate.opsForValue().get(oldRedisRoomKey);
                if (roomRedis.getWxId1().equals(playRedis.getWxId())) roomRedis.setWxId1(null);
                else if (roomRedis.getWxId2().equals(playRedis.getWxId())) roomRedis.setWxId2(null);
                else if (roomRedis.getWxId3().equals(playRedis.getWxId())) roomRedis.setWxId3(null);

                redisTemplate.opsForValue().set(oldRedisRoomKey, roomRedis, 1, TimeUnit.HOURS);
            }

            RoomRedis roomRedis = new RoomRedis();
            roomRedis.setWxId1(data.getFinalFromWxid());
            roomRedis.setPositionWxId(data.getFromWxid());
            roomRedis.setStatus(1);
            roomRedis.setRoomNo(roomNo);
            redisTemplate.opsForValue().set(redisKey, roomRedis, 1, TimeUnit.HOURS);

            playRedis.setRoomNo(roomNo);
            redisTemplate.opsForValue().set(playRedisKey, playRedis, 1, TimeUnit.HOURS);

            WxUtil.sendMessage(data.getFromWxid(), WxUtil.at(data.getFinalFromWxid()) + "创建房间成功");

        } catch (Exception e) {
            e.printStackTrace();
            WxUtil.sendMessage(data.getFromWxid(), WxUtil.at(data.getFinalFromWxid()) + "格式错误");
        }
    }

    private boolean findRoom(GroupReceiveMessage data) {
        String msg = data.getMsg();
        String roomNo = msg.split("#")[1];


        String redisKey = StrUtil.format(RedisKeyConst.DouDiZhuRoomInfo, data.getFromWxid(), roomNo);
        if (Boolean.TRUE.equals(redisTemplate.hasKey(redisKey))) {
            douDiZhuInstruction(data);
            joinRoom(data);
            return true;
        }
        return false;
    }

    private void joinRoom(GroupReceiveMessage data) {

        try {
            String msg = data.getMsg();
            String roomNo = msg.split("#")[1];


            String redisKey = StrUtil.format(RedisKeyConst.DouDiZhuRoomInfo, data.getFromWxid(), roomNo);

            String playRedisKey = StrUtil.format(RedisKeyConst.DouDiZhuPlayInfo, data.getFinalFromWxid(), data.getFromWxid());
            PlayRedis playRedis = (PlayRedis) redisTemplate.opsForValue().get(playRedisKey);

            if (StrUtil.isNotEmpty(playRedis.getRoomNo())) {
                WxUtil.sendMessage(data.getFromWxid(), WxUtil.at(data.getFinalFromWxid()) + "请先退出当前房间");
                return;
            }

            if (Boolean.FALSE.equals(redisTemplate.hasKey(redisKey))) {
                WxUtil.sendMessage(data.getFromWxid(), WxUtil.at(data.getFinalFromWxid()) + "未找到房间");
                return;
            }

            RoomRedis roomRedis = (RoomRedis) redisTemplate.opsForValue().get(redisKey);
            if (StrUtil.isEmpty(roomRedis.getWxId1())) {
                roomRedis.setWxId1(playRedis.getWxId());
            } else if (StrUtil.isEmpty(roomRedis.getWxId2())) {
                roomRedis.setWxId2(playRedis.getWxId());
            } else if (StrUtil.isEmpty(roomRedis.getWxId3())) {
                roomRedis.setWxId3(playRedis.getWxId());
            } else {
                WxUtil.sendMessage(data.getFromWxid(), WxUtil.at(data.getFinalFromWxid()) + "房间已满员");
                return;
            }
            roomRedis.setStatus(1);

            redisTemplate.opsForValue().set(redisKey, roomRedis, 1, TimeUnit.HOURS);

            playRedis.setRoomNo(roomNo);
            redisTemplate.opsForValue().set(playRedisKey, playRedis, 1, TimeUnit.HOURS);


            WxUtil.sendMessage(data.getFromWxid(), WxUtil.at(data.getFinalFromWxid()) + "加入房间成功");


        } catch (Exception e) {
            e.printStackTrace();
            WxUtil.sendMessage(data.getFromWxid(), WxUtil.at(data.getFinalFromWxid()) + "格式错误");
        }
    }


    private void exitRoom(GroupReceiveMessage data) {
        try {
            String msg = data.getMsg();


            String playRedisKey = StrUtil.format(RedisKeyConst.DouDiZhuPlayInfo, data.getFinalFromWxid(), data.getFromWxid());
            PlayRedis playRedis = (PlayRedis) redisTemplate.opsForValue().get(playRedisKey);

            String roomNo = playRedis.getRoomNo();
            if (StrUtil.isEmpty(playRedis.getRoomNo())) {
                WxUtil.sendMessage(data.getFromWxid(), WxUtil.at(data.getFinalFromWxid()) + "未找到房间");
                return;
            }

            String redisKey = StrUtil.format(RedisKeyConst.DouDiZhuRoomInfo, data.getFromWxid(), roomNo);
            RoomRedis roomRedis = (RoomRedis) redisTemplate.opsForValue().get(redisKey);
            if (roomRedis.getStatus() != 1) {
                WxUtil.sendMessage(data.getFromWxid(), WxUtil.at(data.getFinalFromWxid()) + "请等待游戏结束再退出");
                return;
            }
            if (playRedis.getWxId().equals(roomRedis.getWxId1())) {
                roomRedis.setWxId1(null);
            } else if (playRedis.getWxId().equals(roomRedis.getWxId2())) {
                roomRedis.setWxId2(null);
            } else if (playRedis.getWxId().equals(roomRedis.getWxId3())) {
                roomRedis.setWxId3(null);
            } else {
                WxUtil.sendMessage(data.getFromWxid(), WxUtil.at(data.getFinalFromWxid()) + "不在这个房间");
                return;
            }
            redisTemplate.opsForValue().set(redisKey, roomRedis, 1, TimeUnit.HOURS);

            playRedis.setRoomNo(null);
            redisTemplate.opsForValue().set(playRedisKey, playRedis, 1, TimeUnit.HOURS);


            WxUtil.sendMessage(data.getFromWxid(), WxUtil.at(data.getFinalFromWxid()) + "退出房间成功");

        } catch (Exception e) {
            e.printStackTrace();
            WxUtil.sendMessage(data.getFromWxid(), WxUtil.at(data.getFinalFromWxid()) + "格式错误");
        }
    }


    private void startGame(GroupReceiveMessage data) {

        PlayRedis playInfo = getPlayInfo(data.getFromWxid(), data.getFinalFromWxid());
        if (StrUtil.isEmpty(playInfo.getRoomNo())) {
            WxUtil.sendMessage(data.getFromWxid(), WxUtil.at(data.getFinalFromWxid()) + "请先加入 或者 创建房间");
            return;
        }
        RoomRedis roomRedis = getRoomInfo(data.getFromWxid(), playInfo.getRoomNo());
        if (roomRedis == null) {
            WxUtil.sendMessage(data.getFromWxid(), WxUtil.at(data.getFinalFromWxid()) + "房间已销毁,请重新加入 或者 创建房间");
            playInfo.setRoomNo(null);
            setPlayInfo(playInfo);
            return;
        }
        if (roomRedis.getStatus() != 1) {
            WxUtil.sendMessage(data.getFromWxid(), WxUtil.at(data.getFinalFromWxid()) + "房间状态错误");
            return;
        }
        if (StrUtil.isEmpty(roomRedis.getWxId1()) || StrUtil.isEmpty(roomRedis.getWxId2()) || StrUtil.isEmpty(roomRedis.getWxId3())) {
            WxUtil.sendMessage(data.getFromWxid(), WxUtil.at(data.getFinalFromWxid()) + "需要三人才可以开始游戏");
            return;
        }

        List<Puke> pukes = PukeUtil.initPuke();
        //洗牌
        Collections.shuffle(pukes);

        //取出三位玩家
        String playRedisKey1 = StrUtil.format(RedisKeyConst.DouDiZhuPlayInfo, roomRedis.getWxId1(), roomRedis.getPositionWxId());
        String playRedisKey2 = StrUtil.format(RedisKeyConst.DouDiZhuPlayInfo, roomRedis.getWxId2(), roomRedis.getPositionWxId());
        String playRedisKey3 = StrUtil.format(RedisKeyConst.DouDiZhuPlayInfo, roomRedis.getWxId3(), roomRedis.getPositionWxId());

        PlayRedis playRedis1 = (PlayRedis) redisTemplate.opsForValue().get(playRedisKey1);
        playRedis1.setCard(new ArrayList<>());
        PlayRedis playRedis2 = (PlayRedis) redisTemplate.opsForValue().get(playRedisKey2);
        playRedis2.setCard(new ArrayList<>());
        PlayRedis playRedis3 = (PlayRedis) redisTemplate.opsForValue().get(playRedisKey3);
        playRedis3.setCard(new ArrayList<>());
        PlayRedis[] players = {playRedis1, playRedis2, playRedis3};


        //WxUtil.sendMessage(roomRedis.getPositionWxId(), WxUtil.at(playRedis1.getWxId()) + WxUtil.at(playRedis2.getWxId()) + WxUtil.at(playRedis3.getWxId()) + " 房间人数已满,自动开始游戏");

        Puke[] dizhupai = new Puke[3];
        //地主牌
        for (int i = 0; i < 3; i++) {
            int random = new Random().nextInt(pukes.size());
            dizhupai[i] = pukes.get(random);
            pukes.remove(random);
        }
        roomRedis.setDiZhuCard(CollUtil.newArrayList(dizhupai));
        //发牌
        for (int i = 0; i < pukes.size(); i++) {
            players[i % 3].getCard().add(pukes.get(i));


        }
        for (PlayRedis player : players) {
            //排序
            List<Puke> card = player.getCard().stream().sorted(new MyComparator()).collect(Collectors.toList());
            player.setCard(card);
            // 组装牌
            sendPuke(player.getCard(), player.getWxId());
            setPlayInfo(player);
        }


        WxUtil.sendMessage(roomRedis.getPositionWxId(), WxUtil.at(playRedis1.getWxId()) + WxUtil.at(playRedis2.getWxId()) + WxUtil.at(playRedis3.getWxId()) + "手牌已通过私聊发送");

        PlayRedis diZhuPlay = RandomUtil.randomEle(players);
        //PlayRedis diZhuPlay = players[1];


        roomRedis.setDiZhuWxId(diZhuPlay.getWxId());
        roomRedis.setStatus(2);

        // 设置房间信息
        setRoomInfo(roomRedis);

        WxUtil.sendMessage(roomRedis.getPositionWxId(), WxUtil.at(diZhuPlay.getWxId()) + "是否抢地主: 抢地主/不抢");

    }


    private void qiangDiZhu(GroupReceiveMessage data) {
        PlayRedis playInfo = getPlayInfo(data.getFromWxid(), data.getFinalFromWxid());
        if (StrUtil.isEmpty(playInfo.getRoomNo())) {
            WxUtil.sendMessage(data.getFromWxid(), WxUtil.at(data.getFinalFromWxid()) + "请先加入 或者 创建房间");
            return;
        }
        RoomRedis roomInfo = getRoomInfo(data.getFromWxid(), playInfo.getRoomNo());
        if (roomInfo == null) {
            WxUtil.sendMessage(data.getFromWxid(), WxUtil.at(data.getFinalFromWxid()) + "房间已销毁,请重新加入 或者 创建房间");
            playInfo.setRoomNo(null);
            setPlayInfo(playInfo);
            return;
        }
        if (roomInfo.getStatus() != 2) {
            WxUtil.sendMessage(data.getFromWxid(), WxUtil.at(data.getFinalFromWxid()) + "房间状态错误");
            return;
        }

        if (!roomInfo.getDiZhuWxId().equals(data.getFinalFromWxid())) {
            WxUtil.sendMessage(data.getFromWxid(), WxUtil.at(data.getFinalFromWxid()) + "不该你抢地主");
            return;
        }

        if (data.getMsg().equals("抢地主")) {
            roomInfo.setFinalDiZhuWxId(roomInfo.getDiZhuWxId());
            roomInfo.setStatus(3);
            roomInfo.setPlayWxId(roomInfo.getFinalDiZhuWxId());
            roomInfo.setPlayCardType(0);
            roomInfo.setOutCardList(new ArrayList<>());
            setRoomInfo(roomInfo);

            WxUtil.sendMessage(data.getFromWxid(), "抢地主成功 底牌" + CollUtil.join(roomInfo.getDiZhuCard().stream().map(Puke::getNum).map(PukeUtil::translation).toList(), ",") + outCardStr(data.getFinalFromWxid(), roomInfo));
            playInfo.getCard().addAll(roomInfo.getDiZhuCard());
            playInfo.setCard(playInfo.getCard().stream().sorted(new MyComparator()).collect(Collectors.toList()));
            setPlayInfo(playInfo);
            sendPuke(playInfo.getCard(), playInfo.getWxId());

            return;
        }
        if (data.getMsg().equals("不抢")) {
            // 下个人
            roomInfo.setDiZhuWxId(nextWxId(roomInfo, roomInfo.getDiZhuWxId()));
            setRoomInfo(roomInfo);
            WxUtil.sendMessage(roomInfo.getPositionWxId(), WxUtil.at(roomInfo.getDiZhuWxId()) + "是否抢地主: 抢地主/不抢");
        }


    }


    /**
     * 出牌
     *
     * @param data
     */
    private void playCard(GroupReceiveMessage data) {
        PlayRedis playInfo = getPlayInfo(data.getFromWxid(), data.getFinalFromWxid());
        if (StrUtil.isEmpty(playInfo.getRoomNo())) {
            WxUtil.sendMessage(data.getFromWxid(), WxUtil.at(data.getFinalFromWxid()) + "请先加入 或者 创建房间");
            return;
        }
        RoomRedis roomInfo = getRoomInfo(data.getFromWxid(), playInfo.getRoomNo());
        if (roomInfo == null) {
            WxUtil.sendMessage(data.getFromWxid(), WxUtil.at(data.getFinalFromWxid()) + "房间已销毁,请重新加入 或者 创建房间");
            playInfo.setRoomNo(null);
            setPlayInfo(playInfo);
            return;
        }
        if (roomInfo.getStatus() != 3) {
            WxUtil.sendMessage(data.getFromWxid(), WxUtil.at(data.getFinalFromWxid()) + "房间状态错误");
            return;
        }
        if (!roomInfo.getPlayWxId().equals(data.getFinalFromWxid())) {
            WxUtil.sendMessage(data.getFromWxid(), WxUtil.at(data.getFinalFromWxid()) + "不该你出牌");
            return;
        }

        try {
            String msg = data.getMsg();
            if (msg.startsWith("#")) msg = "出" + msg;
            ArrayList<String> cardListStr = CollectionUtil.newArrayList(msg.split("#"));
            cardListStr.remove(0);
            cardListStr = CollectionUtil.newArrayList(cardListStr.get(0).split(" "));

            List<Integer> cardList = cardListStr.stream().map(PukeUtil::translation).collect(Collectors.toList());


            if (!checkCardContains(playInfo.getCard(), cardList)) {
                WxUtil.sendMessage(data.getFromWxid(), WxUtil.at(data.getFinalFromWxid()) + "你出的牌与手牌不匹配");
                return;
            }
            CardStatusDTO cardStatus = getCardStatus(cardList);
            if (cardStatus.getType() == -1) {
                WxUtil.sendMessage(data.getFromWxid(), WxUtil.at(data.getFinalFromWxid()) + "不能这样出哦");
                return;
            }
            // 不是首次
            if (roomInfo.getPlayCardType() != 0) {
                CardStatusDTO beforePukes = roomInfo.getOutCardList().get(roomInfo.getOutCardList().size() - 1);

                if (roomInfo.getPlayCardType() != cardStatus.getType() && cardStatus.getType() != 7) {
                    // 上次出牌
                    WxUtil.sendMessage(data.getFromWxid(), WxUtil.at(data.getFinalFromWxid()) + "出牌类型不符合,上家的牌是 " + CollUtil.join(beforePukes.getCards().stream().map(PukeUtil::translation).toList(), ",") + " 类型:" + PukeUtil.typeTrans(beforePukes.getType()));
                    return;
                }
                if (comparisonCard(beforePukes.getMainCard(), cardStatus.getMainCard(), beforePukes.getType(), cardStatus.getType()) <= 0) {
                    // 上次出牌
                    WxUtil.sendMessage(data.getFromWxid(), WxUtil.at(data.getFinalFromWxid()) + "压不过上家的牌 上家的牌是 " + CollUtil.join(beforePukes.getCards().stream().map(PukeUtil::translation).toList(), ",") + " 类型:" + PukeUtil.typeTrans(beforePukes.getType()));
                    return;
                }

            }

            // 下一位出
            roomInfo.setPlayWxId(nextWxId(roomInfo, roomInfo.getPlayWxId()));
            roomInfo.setWheelInitWxId(data.getFinalFromWxid());
            roomInfo.setPlayCardType(cardStatus.getType());
            roomInfo.addOutCard(cardStatus);
            playInfo.setCard(removePuke(playInfo.getCard(), cardList));
            sendPuke(playInfo.getCard(), playInfo.getWxId());


            WxUtil.sendMessage(data.getFromWxid(), WxUtil.at(data.getFinalFromWxid()) + "出牌成功: " + CollUtil.join(cardStatus.getCards().stream().map(PukeUtil::translation).toList(), ",") + " 类型: " + PukeUtil.typeTrans(cardStatus.getType()) + " 还有 " + playInfo.getCard().size() + " 张牌");
            Thread.sleep(100);

            if (playInfo.getCard().size() == 0) {
                String identity = getIdentity(data.getFinalFromWxid(), roomInfo);
                List<String> wxIdByIdentity = getWxIdByIdentity(roomInfo, identity);
                StringBuilder atStr = new StringBuilder();
                for (String wx : wxIdByIdentity) {
                    atStr.append(WxUtil.at(wx));

                }
                WxUtil.sendMessage(data.getFromWxid(), "[玫瑰] [玫瑰] [玫瑰] [玫瑰] [玫瑰] [玫瑰] 恭喜 " + atStr + getIdentity(data.getFinalFromWxid(), roomInfo) + "取得最终的胜利 [玫瑰] [玫瑰] [玫瑰] [玫瑰] [玫瑰] [玫瑰]");

                roomInfo.setStatus(1);
                roomInfo.setDiZhuCard(new ArrayList<>());
                roomInfo.setOutCardList(new ArrayList<>());
                setRoomInfo(roomInfo);
                return;
            }

            if (playInfo.getCard().size() <= 3) {
                WxUtil.sendMessage(data.getFromWxid(), atIdentity(data.getFinalFromWxid(), roomInfo) + "只剩" + playInfo.getCard().size() + "张牌了 [奸笑][奸笑][奸笑]");
            }


            Thread.sleep(100);
            // 下一位出牌
            WxUtil.sendMessage(data.getFromWxid(), outCardStr(roomInfo.getPlayWxId(), roomInfo));
            setPlayInfo(playInfo);
            setRoomInfo(roomInfo);

        } catch (Exception e) {
            e.printStackTrace();
            WxUtil.sendMessage(data.getFromWxid(), WxUtil.at(data.getFinalFromWxid()) + "格式错误");
        }

    }

    private List<String> getWxIdByIdentity(RoomRedis roomInfo, String identity) {
        String identity1 = getIdentity(roomInfo.getWxId1(), roomInfo);
        String identity2 = getIdentity(roomInfo.getWxId2(), roomInfo);
        String identity3 = getIdentity(roomInfo.getWxId3(), roomInfo);
        List<String> wxIds = new ArrayList<>(2);
        if (identity1.equals(identity)) wxIds.add(roomInfo.getWxId1());
        if (identity2.equals(identity)) wxIds.add(roomInfo.getWxId2());
        if (identity3.equals(identity)) wxIds.add(roomInfo.getWxId3());

        return wxIds;
    }

    private void noPlayCard(GroupReceiveMessage data) {
        PlayRedis playInfo = getPlayInfo(data.getFromWxid(), data.getFinalFromWxid());
        if (StrUtil.isEmpty(playInfo.getRoomNo())) {
            WxUtil.sendMessage(data.getFromWxid(), WxUtil.at(data.getFinalFromWxid()) + "请先加入 或者 创建房间");
            return;
        }
        RoomRedis roomInfo = getRoomInfo(data.getFromWxid(), playInfo.getRoomNo());
        if (roomInfo == null) {
            WxUtil.sendMessage(data.getFromWxid(), WxUtil.at(data.getFinalFromWxid()) + "房间已销毁,请重新加入 或者 创建房间");
            playInfo.setRoomNo(null);
            setPlayInfo(playInfo);
            return;
        }
        if (roomInfo.getStatus() != 3) {
            WxUtil.sendMessage(data.getFromWxid(), WxUtil.at(data.getFinalFromWxid()) + "房间状态错误");
            return;
        }
        if (!roomInfo.getPlayWxId().equals(data.getFinalFromWxid())) {
            WxUtil.sendMessage(data.getFromWxid(), WxUtil.at(data.getFinalFromWxid()) + "不该你出牌");
            return;
        }

        try {
            // 下一位出
            roomInfo.setPlayWxId(nextWxId(roomInfo, roomInfo.getPlayWxId()));
            if (roomInfo.getPlayWxId().equals(roomInfo.getWheelInitWxId())) {
                roomInfo.setPlayCardType(0);
                // 下一位出牌
                WxUtil.sendMessage(data.getFromWxid(), "没有人能大过你的牌 " + outCardStr(roomInfo.getPlayWxId(), roomInfo));
            } else {
                // 下一位出牌
                WxUtil.sendMessage(data.getFromWxid(), outCardStr(roomInfo.getPlayWxId(), roomInfo));
            }


            setRoomInfo(roomInfo);
        } catch (Exception e) {
            e.printStackTrace();
            WxUtil.sendMessage(data.getFromWxid(), WxUtil.at(data.getFinalFromWxid()) + "格式错误");
        }

    }

    private List<Puke> removePuke(List<Puke> pukes1, List<Integer> outCard) {
        List<Puke> newPuke = new ArrayList<>();
        for (Puke puke : pukes1) {
            if (outCard.contains(puke.getNum())) {
                outCard.remove(outCard.indexOf(puke.getNum()));
                continue;
            }
            newPuke.add(puke);
        }
        return newPuke;
    }

    private String outCardStr(String wxId, RoomRedis roomRedis) {
        return StrUtil.format(atIdentity(wxId, roomRedis) + "请出牌: \n出牌指令 出#3 4 5 6 7 \n不要指令: 不要");
    }

    private String atIdentity(String wxId, RoomRedis roomRedis) {
        return getIdentity(wxId, roomRedis) + WxUtil.at(wxId);
    }

    private String getIdentity(String wxId, RoomRedis roomRedis) {
        String prefix = "";
        if (roomRedis.getFinalDiZhuWxId().equals(wxId)) prefix = "地主 ";
        else prefix = "农民 ";
        return prefix;
    }

    /**
     * 判断哪个大
     *
     * @param mainCard1
     * @param mainCard2
     * @return
     */
    private int comparisonCard(List<Integer> mainCard1, List<Integer> mainCard2, int beforeType, int currentType) {
        mainCard1 = mainCard1.stream().sorted().collect(Collectors.toList());

        mainCard2 = mainCard2.stream().sorted().collect(Collectors.toList());

        int comparison = switch (beforeType) {
            case 1, 2, 4, 5, 6, 7, 12, 13 -> mainCard2.get(0) - mainCard1.get(0);
            case 3, 8, 9, 10, 11, 14, 15, 16 -> {
                if (mainCard1.size() != mainCard2.size())
                    throw new IllegalArgumentException("与上家牌不符");
                yield mainCard2.get(0) - mainCard1.get(0);
            }
            default -> throw new IllegalStateException("Unexpected value: " + beforeType);
        };
        if (beforeType != 7 && currentType == 7) {
            return 1;
        }
        return comparison;
    }

    /**
     * @param playCard
     * @return
     */
    private CardStatusDTO getCardStatus(List<Integer> playCard) {
        CardStatusDTO cardStatusDTO = new CardStatusDTO();
        playCard = playCard.stream().sorted().collect(Collectors.toList());
        cardStatusDTO.setCards(playCard);

        if (playCard.size() == 1) {
            cardStatusDTO.setType(1);
            cardStatusDTO.setMainCard(playCard);
            return cardStatusDTO;
        }

        if (playCard.size() == 2 && playCard.get(0).equals(playCard.get(1))) {
            cardStatusDTO.setType(2);
            cardStatusDTO.setMainCard(playCard);
            return cardStatusDTO;
        }

        if (playCard.size() == 3 && playCard.get(0).equals(playCard.get(1)) && playCard.get(1).equals(playCard.get(2))) {
            cardStatusDTO.setType(3);
            cardStatusDTO.setMainCard(playCard);
            return cardStatusDTO;
        }

        if (playCard.size() == 4) {
            // 炸
            if (playCard.get(0).equals(playCard.get(1)) && playCard.get(1).equals(playCard.get(2)) && playCard.get(2).equals(playCard.get(3))) {
                cardStatusDTO.setType(7);
                cardStatusDTO.setMainCard(playCard);
                return cardStatusDTO;
            }
            Map<Integer, List<Integer>> pukesMap = playCard.stream().collect(Collectors.groupingBy(Integer::intValue));
            Set<Integer> keySet = pukesMap.keySet();
            ArrayList<Integer> keys = CollUtil.newArrayList(keySet);

            if (pukesMap.get(keys.get(0)).size() == 3 || pukesMap.get(keys.get(1)).size() == 3) {
                cardStatusDTO.setType(5);
                cardStatusDTO.setMainCard(pukesMap.get(keys.get(0)).size() == 3 ? pukesMap.get(keys.get(0)) : pukesMap.get(keys.get(1)));
                return cardStatusDTO;
            }
        }

        // 三带二
        if (playCard.size() == 5) {
            // 三带2
            Map<Integer, List<Integer>> pukesMap = playCard.stream().collect(Collectors.groupingBy(Integer::intValue));
            Set<Integer> keySet = pukesMap.keySet();
            ArrayList<Integer> keys = CollUtil.newArrayList(keySet);

            if (pukesMap.get(keys.get(0)).size() == 3 && pukesMap.get(keys.get(1)).size() == 2) {
                cardStatusDTO.setType(6);
                cardStatusDTO.setMainCard(pukesMap.get(keys.get(0)));
                return cardStatusDTO;
            }
            if (pukesMap.get(keys.get(1)).size() == 3 && pukesMap.get(keys.get(0)).size() == 2) {
                cardStatusDTO.setType(6);
                cardStatusDTO.setMainCard(pukesMap.get(keys.get(1)));
                return cardStatusDTO;
            }
        }

        // 王炸
        if (playCard.size() == 2 && (playCard.get(0) == 99 && playCard.get(1) == 999)) {
            cardStatusDTO.setType(7);
            cardStatusDTO.setMainCard(playCard);
            return cardStatusDTO;
        }


        // 是不是顺子
        if (playCard.size() >= 5 && (!playCard.contains(15)) && (!playCard.contains(99)) && (!playCard.contains(999))) {

            for (int i = 1; i < playCard.size(); i++) {
                int beforeValue = playCard.get(i) - 1;
                if (beforeValue != playCard.get(i - 1)) break;

                // 最后一个 三
                if (playCard.size() == (i + 1)) {
                    cardStatusDTO.setType(3);
                    cardStatusDTO.setMainCard(playCard);
                    return cardStatusDTO;
                }
            }
        }

        // 是不是 双连
        if (playCard.size() >= 6 && (!playCard.contains(15)) && (!playCard.contains(99)) && (!playCard.contains(999))) {
            Map<Integer, List<Integer>> pukesMap = playCard.stream().collect(Collectors.groupingBy(Integer::intValue));
            Set<Integer> keySet = pukesMap.keySet();
            ArrayList<Integer> keys = CollUtil.newArrayList(keySet);
            List<Integer> sortKeys = keys.stream().sorted().toList();
            if (sortKeys.size() >= 3) {
                for (int i = 1; i < sortKeys.size(); i++) {
                    int beforeValue = pukesMap.get(sortKeys.get(i)).get(0) - 1;
                    if (beforeValue != pukesMap.get(sortKeys.get(i - 1)).get(0)) break;
                    if (pukesMap.get(sortKeys.get(i)).size() != 2) break;

                    if (sortKeys.size() == (i + 1) && (pukesMap.get(sortKeys.get(0)).size() == 2)) {
                        cardStatusDTO.setType(8);
                        cardStatusDTO.setMainCard(playCard);
                        return cardStatusDTO;
                    }
                }
            }
        }

        // 是不是三连
        if (playCard.size() >= 6) {

            // 把三个的取出来
            List<Integer> three = new ArrayList<>();
            Map<Integer, List<Integer>> pukesMap = playCard.stream().collect(Collectors.groupingBy(Integer::intValue));
            for (Integer key : pukesMap.keySet()) {
                if (pukesMap.get(key).size() == 3) {
                    three.add(key);
                }
            }

            if (three.size() != 0) {
                // 获取连续的牌
                List<List<Integer>> continuousPukeList = new ArrayList<>();
                List<Integer> continuous = new ArrayList<>();
                for (int i = 0; i < three.size(); i++) {
                    int beforeValue = three.get(i) + 1;
                    if (i != three.size() - 1 && beforeValue == three.get(i + 1)) {
                        continuous.add(three.get(i));
                    } else {
                        continuous.add(three.get(i));
                        continuousPukeList.add(continuous);
                        continuous = new ArrayList<>();
                    }
                }

                // 获取最大的连续牌
                List<Integer> maxContinuous = new ArrayList<>();
                maxContinuous = continuousPukeList.get(0);
                for (List<Integer> continuousPuke : continuousPukeList) {
                    if (continuousPuke.size() > maxContinuous.size()) {
                        maxContinuous = continuousPuke;
                    }
                }

                List<Integer> remainingPuke = new ArrayList<>();
                // 计算剩余的牌
                for (Integer card : playCard) {
                    if (!maxContinuous.contains(card)) {
                        remainingPuke.add(card);
                    }
                }

                if (remainingPuke.size() == 0) {
                    cardStatusDTO.setType(9);
                    cardStatusDTO.setMainCard(playCard);
                    return cardStatusDTO;
                }
                if (remainingPuke.size() == maxContinuous.size()) {
                    cardStatusDTO.setType(10);
                    cardStatusDTO.mainCardTrans(maxContinuous, 3);
                    return cardStatusDTO;
                }

                if (remainingPuke.size() == maxContinuous.size() * 2) {
                    Map<Integer, List<Integer>> remainingPukeMap = remainingPuke.stream().collect(Collectors.groupingBy(Integer::intValue));
                    Set<Integer> keySet = remainingPukeMap.keySet();
                    ArrayList<Integer> keys = CollUtil.newArrayList(keySet);
                    for (int i = 0; i < keys.size(); i++) {
                        if (remainingPukeMap.get(keys.get(i)).size() != 2) {
                            break;
                        }
                        if (i == keys.size() - 1) {
                            cardStatusDTO.setType(11);
                            cardStatusDTO.mainCardTrans(maxContinuous, 3);
                            return cardStatusDTO;
                        }
                    }
                }

            }


        }


        // 是不是四连
        if (playCard.size() >= 4) {

            // 把四个的取出来
            List<Integer> iv = new ArrayList<>();
            Map<Integer, List<Integer>> pukesMap = playCard.stream().collect(Collectors.groupingBy(Integer::intValue));
            for (Integer key : pukesMap.keySet()) {
                if (pukesMap.get(key).size() == 4) {
                    iv.add(key);
                }
            }


            // 获取连续的牌
            if (iv.size() != 0) {
                List<List<Integer>> continuousPukeList = new ArrayList<>();
                List<Integer> continuous = new ArrayList<>();
                for (int i = 0; i < iv.size(); i++) {
                    int beforeValue = iv.get(i) + 1;
                    if (i != iv.size() - 1 && beforeValue == iv.get(i + 1)) {
                        continuous.add(iv.get(i));
                    } else {
                        continuous.add(iv.get(i));
                        continuousPukeList.add(continuous);
                        continuous = new ArrayList<>();
                    }
                }

                // 获取最大的连续牌
                List<Integer> maxContinuous = new ArrayList<>();
                maxContinuous = continuousPukeList.get(0);
                for (List<Integer> continuousPuke : continuousPukeList) {
                    if (continuousPuke.size() > maxContinuous.size()) {
                        maxContinuous = continuousPuke;
                    }
                }

                List<Integer> remainingPuke = new ArrayList<>();
                // 计算剩余的牌
                for (Integer card : playCard) {
                    if (!maxContinuous.contains(card)) {
                        remainingPuke.add(card);
                    }
                }
                if (remainingPuke.size() == 0) {
                    cardStatusDTO.setType(14);
                    cardStatusDTO.mainCardTrans(maxContinuous, 4);
                    return cardStatusDTO;
                }
                if (remainingPuke.size() == maxContinuous.size() * 2) {
                    cardStatusDTO.setType(maxContinuous.size() == 1 ? 12 : 15);
                    cardStatusDTO.mainCardTrans(maxContinuous, 4);
                    return cardStatusDTO;
                }


                if (remainingPuke.size() == maxContinuous.size() * 4) {
                    Map<Integer, List<Integer>> remainingPukeMap = remainingPuke.stream().collect(Collectors.groupingBy(Integer::intValue));
                    Set<Integer> keySet = remainingPukeMap.keySet();
                    ArrayList<Integer> keys = CollUtil.newArrayList(keySet);
                    for (int i = 0; i < keys.size(); i++) {
                        if (remainingPukeMap.get(keys.get(i)).size() != 2) {
                            break;
                        }
                        if (i == keys.size() - 1) {
                            cardStatusDTO.setType(maxContinuous.size() == 1 ? 13 : 16);
                            cardStatusDTO.mainCardTrans(maxContinuous, 4);
                            return cardStatusDTO;
                        }
                    }
                }
            }

        }

        cardStatusDTO.setType(-1);
        return cardStatusDTO;
    }


    private boolean checkCardContains(List<Puke> pukes, List<Integer> playCard) {
        List<Puke> newPukes = JSON.parseArray(JSON.toJSONString(pukes), Puke.class);
        Map<Integer, List<Puke>> pukesMap = newPukes.stream().collect(Collectors.groupingBy(Puke::getNum));

        for (Integer num : playCard) {
            List<Puke> pukeList = pukesMap.get(num);
            if (pukeList == null || CollUtil.isEmpty(pukeList)) return false;
            pukeList.remove(0);
            pukesMap.put(num, pukeList);
        }
        return true;
    }

    /**
     * 获取下一个微信id
     *
     * @param roomRedis
     * @param wxId
     * @return
     */
    private String nextWxId(RoomRedis roomRedis, String wxId) {
        if (roomRedis.getWxId1().equals(wxId)) return roomRedis.getWxId2();
        if (roomRedis.getWxId2().equals(wxId)) return roomRedis.getWxId3();
        if (roomRedis.getWxId3().equals(wxId)) return roomRedis.getWxId1();
        return null;
    }


    private void setRoomInfo(RoomRedis roomRedis) {
        String redisKey = StrUtil.format(RedisKeyConst.DouDiZhuRoomInfo, roomRedis.getPositionWxId(), roomRedis.getRoomNo());
        redisTemplate.opsForValue().set(redisKey, roomRedis, 1, TimeUnit.HOURS);
    }

    private void setPlayInfo(PlayRedis playRedis) {
        String playRedisKey = StrUtil.format(RedisKeyConst.DouDiZhuPlayInfo, playRedis.getWxId(), playRedis.getPositionWxid());
        redisTemplate.opsForValue().set(playRedisKey, playRedis, 1, TimeUnit.HOURS);
    }

    private RoomRedis getRoomInfo(String positionWxId, String roomNo) {
        String redisKey = StrUtil.format(RedisKeyConst.DouDiZhuRoomInfo, positionWxId, roomNo);
        return (RoomRedis) redisTemplate.opsForValue().get(redisKey);
    }

    private PlayRedis getPlayInfo(String positionWxId, String wxId) {
        String playRedisKey = StrUtil.format(RedisKeyConst.DouDiZhuPlayInfo, wxId, positionWxId);
        return (PlayRedis) redisTemplate.opsForValue().get(playRedisKey);
    }


    private void sendPuke(List<Puke> pukes, String wxId) {
        StringBuffer sb = new StringBuffer();
        for (Puke puke : pukes) {
            sb.append(PukeUtil.translation(puke.getNum()) + ", ");
        }
        if (sb.isEmpty()) return;

        String rest = sb.toString().substring(0, sb.toString().length() - 2);
        WxUtil.sendMessage(wxId, "您的手牌: " + rest);
    }

}
